using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.OracleClient;
using System.Data.OleDb;
using System.Data.Odbc;

namespace QidorSpider.Components.Data
{
    [Serializable]
    public sealed class QueryParameter : MarshalByRefObject, IDbDataParameter, ICloneable
    {
        private ParameterDirection m_direction;
        private bool m_forceSize;
        //private bool m_inferType;
        private bool m_isNullable;
        private string m_name;
        private int m_offset;
        //private SqlParameterCollection m_parent;
        private byte m_precision;
        private byte m_scale;
        private int m_size;
        private string m_sourceColumn;
        private bool m_suppress;
        private object m_value;
        private DataRowVersion m_version;
        private DbType m_dbType;
        private IDbDataParameter m_realParameter;

        public QueryParameter()
        {
            m_value = null;
            m_direction = ParameterDirection.Input;
            m_size = -1;
            m_version = DataRowVersion.Current;
            m_forceSize = false;
            m_offset = 0;
            m_suppress = false;
            //			m_inferType = true;
        }

        public QueryParameter(string parameterName, object Value)
            : this()
        {
            m_name = parameterName;
            m_value = Value;
        }

        public QueryParameter(string parameterName, object Value, DbType dbType)
            : this()
        {
            m_name = parameterName;
            m_dbType = dbType;
            m_value = Value;
        }

        public QueryParameter(string parameterName, DbType dbType)
            : this()
        {
            m_name = parameterName;
            m_dbType = dbType;
        }

        public QueryParameter(string parameterName, DbType dbType, int size)
            : this()
        {
            m_name = parameterName;
            m_dbType = dbType;
            m_size = size;
        }

        public QueryParameter(string parameterName, DbType dbType, int size, string sourceColumn)
            : this()
        {
            m_name = parameterName;
            m_dbType = dbType;
            m_size = size;
            m_sourceColumn = sourceColumn;
        }

        public QueryParameter(string parameterName, DbType dbType, int size, ParameterDirection direction,
            bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object Value)
            : this()
        {
            m_name = parameterName;
            m_dbType = dbType;
            m_size = size;
            m_direction = direction;
            m_isNullable = isNullable;
            m_precision = precision;
            m_scale = scale;
            m_sourceColumn = sourceColumn;
            m_version = sourceVersion;
            m_value = Value;
        }

        public override string ToString()
        {
            return ParameterName;
        }

        public string ParameterName
        {
            get { return m_name; }
            set { m_name = value; }
        }

        public object Value
        {
            get
            {
                if(Object.Equals(m_value, null))
                    return DBNull.Value;
                else
                    return m_value;
            }
            set { m_value = value; }
        }

        public byte Precision
        {
            get { return m_precision; }
            set { m_precision = value; }
        }

        public int Offset
        {
            get { return m_offset; }
            set { m_offset = value; }
        }

        public byte Scale
        {
            get { return m_scale; }
            set { m_scale = value; }
        }

        public int Size
        {
            get
            {
                if(m_forceSize)
                {
                    return m_size;
                }
                return 0;
            }

            set
            {
                if(value < 0)
                {
                    throw new Exception(value.ToString());
                }

                if(value != 0)
                {
                    m_forceSize = true;
                    m_size = value;
                    return;
                }
                m_forceSize = false;
                m_size = -1;
            }
        }

        public ParameterDirection Direction
        {
            get { return m_direction; }
            set { m_direction = value; }
        }



        public DbType DbType
        {
            get { return m_dbType; }
            set { m_dbType = value; }
        }

        public bool IsNullable
        {
            get { return m_isNullable; }
            set { m_isNullable = value; }
        }

        public DataRowVersion SourceVersion
        {
            get { return m_version; }
            set { m_version = value; }
        }

        public string SourceColumn
        {
            get
            {
                if(m_sourceColumn == null)
                {
                    return string.Empty;
                }
                return m_sourceColumn;
            }
            set
            {
                m_sourceColumn = value;
            }
        }

        internal bool Suppress
        {
            get { return m_suppress; }
            set { m_suppress = value; }
        }

        internal void InitRealParameter(DatabaseType databaseType)
        {
            if(Object.Equals(m_realParameter, null))
            {
                switch(databaseType)
                {
                    case DatabaseType.MSSQLServer:
                        m_realParameter = new SqlParameter();
                        break;
                    case DatabaseType.Oracle:
                        m_realParameter = new OracleParameter();
                        break;
                    case DatabaseType.OleDBSupported:
                        m_realParameter = new OleDbParameter();
                        break;
                }
            }

            RealParameter.DbType = DbType;
            ////
            //OleDbParameter p = new OleDbParameter();
            //    if (m_dbType == DbType.Int32)
            //        p.OleDbType = OleDbType.Integer;
            //    if (m_dbType == DbType.String)
            //        p.OleDbType = OleDbType.VarWChar;
            //m_realParameter = (IDbDataParameter)p;
            RealParameter.Direction = Direction;
            RealParameter.ParameterName = ParameterName;
            RealParameter.Precision = Precision;
            RealParameter.Scale = Scale;
            RealParameter.Size = Size;
            RealParameter.SourceColumn = SourceColumn;
            RealParameter.SourceVersion = SourceVersion;
            RealParameter.Value = Value;
        }

        internal IDbDataParameter RealParameter
        {
            get { return m_realParameter; }
            //set{m_realParameter = value;}
        }

        internal void SyncParameter()
        {
            if(Object.Equals(m_realParameter, null))
                return;
            SetProperties(RealParameter.ParameterName, RealParameter.SourceColumn, RealParameter.SourceVersion, RealParameter.Precision,
                RealParameter.Scale, RealParameter.Size, m_forceSize, m_offset, RealParameter.Direction, RealParameter.Value,
                RealParameter.DbType, Suppress);
        }

        internal void SetProperties(string name, string column, DataRowVersion version, byte precision, byte scale,
            int size, bool forceSize, int offset, ParameterDirection direction, object Value, DbType type, bool suppress)
        {
            ParameterName = name;
            m_sourceColumn = column;
            SourceVersion = version;
            Precision = precision;
            m_scale = scale;
            m_size = size;
            m_forceSize = forceSize;
            m_offset = offset;
            Direction = direction;
            if((Value as ICloneable) != null)
            {
                Value = ((ICloneable)Value).Clone();
            }
            m_value = Value;
            Suppress = suppress;
        }

        #region ICloneable
        public object Clone()
        {
            QueryParameter parameter1;
            parameter1 = new QueryParameter();
            parameter1.SetProperties(m_name, m_sourceColumn, m_version, m_precision, m_scale,
                        m_size, m_forceSize, m_offset, m_direction, m_value, m_dbType, m_suppress);
            return parameter1;
        }

        #endregion

    }

}

